//
//  WCBuildResultsWindowController.m
//  WabbitCode
//
//  Created by William Towe on 3/14/09.
//  Copyright 2009 Revolution Software. All rights reserved.
//

#import "WCBuildResultsWindowController.h"
#import "WCProject.h"
#import "PSMTabBarControl+WCExtensions.h"
#import "WCAppController.h"
#import "WCInterfacePerformer.h"
#import "WCBadgedIconAndTextFieldCell.h"
#import "WCBuildMessage.h"
#import "WCTextView.h"
#import "WCRulerView.h"
#import "NSArray+WCExtensions.h"
#import "WCTextFile.h"
#import "WCSymbol.h"
#import "WCBasicPerformer.h"


NSString *kWCProjectPrefsBuildResultsWindowFrameKey = @"kWCProjectPrefsBuildResultsWindowFrameKey";
NSString *kWCProjectPrefsBuildResultsSplitViewDividerPositionKey = @"kWCProjectPrefsBuildResultsSplitViewDividerPositionKey";

#define kWCBuildResultsWindowToolbarIdentifier @"org.revsoft.wabbitcode.buildresultstoolbar"

@interface WCBuildResultsWindowController (Private)
- (void)_loadProjectPreferences;
@end

@implementation WCBuildResultsWindowController
- (id)init {
	return [self initWithWindowNibName:@"WCBuildResultsWindow"];
}

- (void)dealloc {
	[[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.kWCPrefsTabsAnimateAddingAndRemovingKey"];
	[[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.kWCPrefsTabsAllowScrubbingOfTabsKey"];
	
	[super dealloc];
}

- (void)windowDidLoad {
	[super windowDidLoad];
	
	NSToolbar *toolbar = [[[NSToolbar alloc] initWithIdentifier:kWCBuildResultsWindowToolbarIdentifier] autorelease];
	
#ifndef WCDEBUG
	[toolbar setAutosavesConfiguration:YES];
#endif
	[toolbar setDisplayMode:NSToolbarDisplayModeDefault];
	[toolbar setSizeMode:NSToolbarSizeModeRegular];
	[toolbar setAllowsUserCustomization:YES];
	
	[toolbar setDelegate:self];
	[[self window] setToolbar:toolbar];
	
	[_psmTabBarControl performSetup];
	
	[_textViewActionPopUpButton setMenu:[[WCInterfacePerformer sharedInstance] menuForProjectTextViewActionButton]];
	
	[_projectBuildStatusTextField bind:@"imagesAndStrings" toObject:[self project] withKeyPath:@"buildStatusImagesAndStrings" options:nil];
	
	[_outlineView setTarget:self];
	[_outlineView setDoubleAction:@selector(_outlineViewDoubleAction:)];
	
	[[_textViewSymbolsActionPopUpButton menu] setDelegate:self];
	
	[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.kWCPrefsTabsAnimateAddingAndRemovingKey" options:NSKeyValueObservingOptionNew context:(void *)kWCPrefsTabsAnimateAddingAndRemovingKey];
	[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.kWCPrefsTabsAllowScrubbingOfTabsKey" options:NSKeyValueObservingOptionNew context:(void *)kWCPrefsTabsAllowScrubbingOfTabsKey];
	
	[self _loadProjectPreferences];
}

- (NSString *)windowTitleForDocumentDisplayName:(NSString *)displayName {
	return [NSString stringWithFormat:NSLocalizedString(@"%@ - Build Results",@"%@ - Build Results"), [displayName stringByDeletingPathExtension]];
}
#pragma mark NSToolbar Delegate
- (NSToolbarItem *)toolbar:(NSToolbar *)toolbar itemForItemIdentifier:(NSString *)identifier willBeInsertedIntoToolbar:(BOOL)flag {
	NSToolbarItem *item = [[WCBasicPerformer sharedInstance] toolbarItemForItemIdentifier:identifier inProject:[self project]];
	
	return item;
}

- (NSArray *)toolbarAllowedItemIdentifiers:(NSToolbar *)toolbar {
	return [NSArray arrayWithObjects:kWCProjectToolbarProjectOverviewIdentifier,kWCProjectToolbarBuildIdentifier,kWCProjectToolbarProjectWindowIdentifier, NSToolbarSpaceItemIdentifier, NSToolbarFlexibleSpaceItemIdentifier, NSToolbarSeparatorItemIdentifier, NSToolbarCustomizeToolbarItemIdentifier, nil];
}

- (NSArray *)toolbarDefaultItemIdentifiers:(NSToolbar *)toolbar {
	return [NSArray arrayWithObjects:kWCProjectToolbarProjectOverviewIdentifier,NSToolbarFlexibleSpaceItemIdentifier,kWCProjectToolbarBuildIdentifier,NSToolbarFlexibleSpaceItemIdentifier,kWCProjectToolbarProjectWindowIdentifier, nil];
}
#pragma mark NSSplitView Delegate
- (CGFloat)splitView:(NSSplitView *)splitView constrainMinCoordinate:(CGFloat)proposedMin ofSubviewAt:(NSInteger)offset {
	if (![splitView isVertical])
		return proposedMin + 150.0;
	return proposedMin;
}

- (CGFloat)splitView:(NSSplitView *)splitView constrainMaxCoordinate:(CGFloat)proposedMax ofSubviewAt:(NSInteger)offset {
	if (![splitView isVertical])
		return proposedMax - 150.0;
	return proposedMax;
}

- (void)splitView:(NSSplitView *)splitView resizeSubviewsWithOldSize:(NSSize)oldSize {
	if ([splitView inLiveResize] && ![splitView isVertical]) {
		// keep the top view the same while resizing the bottom view
		NSArray *subviews = [splitView subviews];
		NSView *topView = [subviews objectAtIndex:0];
		NSView *bottomView = [subviews lastObject];
		NSRect currentFrame = [splitView frame];
		NSRect topFrame = [topView frame];
		NSRect bottomFrame = [bottomView frame];
		CGFloat dividerThickness = [splitView dividerThickness];
		
		topFrame.size.width = currentFrame.size.width;
		bottomFrame.size.height = currentFrame.size.height - topFrame.size.height - dividerThickness;
		bottomFrame.size.width = currentFrame.size.width;
		bottomFrame.origin.y = topFrame.size.height + dividerThickness;
		
		[topView setFrame:topFrame];
		[bottomView setFrame:bottomFrame];
	}
	else {
		[splitView adjustSubviews];
	}
}
#pragma mark NSOutlineView Delegate
- (void)outlineView:(NSOutlineView *)outlineView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item {
	[cell setIcon:[[item representedObject] icon]];
	[cell setIconSize:NSMakeSize(16.0, 16.0)];
	
	if ([[item representedObject] messageType] == WCBMTypeFileExpanded)
		[cell setBadgeCount:[[[item representedObject] childNodes] count]];
	else
		[cell setBadgeCount:0];
	
	if ([[item representedObject] messageType] == WCBMTypeError ||
		[[item representedObject] messageType] == WCBMTypeWarning ||
		[[item representedObject] messageType] == WCBMTypeFailureErrors ||
		[[item representedObject] messageType] == WCBMTypeSuccessWarnings ||
		[[item representedObject] messageType] == WCBMTypeBuildSuccess) {
		
		[cell setIconSize:NSMakeSize(14.0, 14.0)];
		
		if ([cell isHighlighted] || ([[item representedObject] messageType] != WCBMTypeError && [[item representedObject] messageType] != WCBMTypeFailureErrors))
			return;
		
		NSMutableAttributedString *string = [[[cell attributedStringValue] mutableCopy] autorelease];
		
		[string addAttribute:NSForegroundColorAttributeName value:[NSColor colorWithCalibratedRed:0.5 green:0.0 blue:0.0 alpha:1.0] range:NSMakeRange(0, [string length])];
		
		[cell setAttributedStringValue:string];
	}
}
#pragma mark NSMenu Delegate
- (NSInteger)numberOfItemsInMenu:(NSMenu *)menu {
	NSUInteger count = [[self currentTextFile] numberOfFileSymbols];
	return (!count)?2:++count;
}

- (BOOL)menu:(NSMenu *)menu updateItem:(NSMenuItem *)item atIndex:(NSInteger)index shouldCancel:(BOOL)shouldCancel {
	NSUInteger count = [[self currentTextFile] numberOfFileSymbols];
	[item setTarget:self];
	[item setAction:@selector(_textViewSymbolsPopUpButtonAction:)];
	if (!count) {
		if (!index) {
			[item setHidden:YES];
			[item setImage:[NSImage imageNamed:NSImageNameListViewTemplate]];
		}
		else {
			[item setTitle:NSLocalizedString(@"No Symbols",@"No Symbols")];
		}
	}
	else {
		if (!index) {
			[item setHidden:YES];
			[item setImage:[NSImage imageNamed:NSImageNameListViewTemplate]];
		}
		else {
			WCSymbol *symbol = [[[self currentTextFile] fileSymbolsArray] objectAtIndex:--index];
			[item setTitle:[NSString stringWithFormat:@"%@ - Line: %u",[symbol name],[symbol lineNumber]+1]];
			[item setImage:[symbol icon]];
			[item setRepresentedObject:symbol];
		}
	}
	return YES;
}
#pragma mark NSKeyValueObserving Protocol
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
	if ([(NSString *)context isEqualToString:kWCPrefsTabsAnimateAddingAndRemovingKey]) {
		[[self psmTabBarControl] setAutomaticallyAnimates:NSUserDefaultsBoolForKey(kWCPrefsTabsAnimateAddingAndRemovingKey)];
	}
	else if ([(NSString *)context isEqualToString:kWCPrefsTabsAllowScrubbingOfTabsKey]) {
		[[self psmTabBarControl] setAllowsScrubbing:NSUserDefaultsBoolForKey(kWCPrefsTabsAllowScrubbingOfTabsKey)];
	}
	/*
	 else if ([(NSString *)context isEqualToString:@"fileURL"]) {
	 [[self projectOutlineView] setNeedsDisplay:YES];
	 [[self fileDetailTableView] setNeedsDisplay:YES];
	 }
	 */
	else {
		[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
	}
}
#pragma mark NSUserInterfaceValidations Protocol
- (BOOL)validateUserInterfaceItem:(id < NSValidatedUserInterfaceItem >)item; {
	SEL action = [item action];
	
	if (action == @selector(_textViewSymbolsPopUpButtonAction:)) {
		if (![self currentTextFile])
			return NO;
	}
	return YES;
}
#pragma mark PSMTabBarControl Delegate
- (BOOL)tabView:(NSTabView *)aTabView shouldCloseTabViewItem:(NSTabViewItem *)item; {
	return [[self project] canRemoveTabViewItem:item inTabViewContext:self];
}
- (void)tabView:(NSTabView *)aTabView didCloseTabViewItem:(NSTabViewItem *)item; {
	[[self project] removeTabViewItem:item inTabViewContext:self saveTextFile:NO];
	if ([self currentTextView])
		[_lineColumnButton bind:@"title" toObject:[self currentTextView] withKeyPath:@"infoString" options:nil];
	else {
		[_lineColumnButton unbind:@"title"];
		[_lineColumnButton setTitle:NSLocalizedString(@"N/A",@"N/A")];
		[_textViewSymbolsActionPopUpButton removeAllItems];
		NSMenuItem *item = [[[NSMenuItem alloc] initWithTitle:@"" action:NULL keyEquivalent:@""] autorelease];
		[item setImage:[NSImage imageNamed:NSImageNameListViewTemplate]];
		[[_textViewSymbolsActionPopUpButton menu] addItem:item];
	}
}

- (void)tabView:(NSTabView *)tabView didSelectTabViewItem:(NSTabViewItem *)item {
	[_lineColumnButton bind:@"title" toObject:[[item view] documentView] withKeyPath:@"infoString" options:nil];
}

- (BOOL)tabView:(NSTabView *)tabView shouldDragTabViewItem:(NSTabViewItem *)tabViewItem fromTabBar:(PSMTabBarControl *)tabBarControl; {
	return ([tabView numberOfTabViewItems] == 1)?NO:YES;
}
- (BOOL)tabView:(NSTabView *)tabView shouldDropTabViewItem:(NSTabViewItem *)tabViewItem inTabBar:(PSMTabBarControl *)tabBarControl; {
	if ([[tabBarControl tabView] isEqualTo:tabView])
		return YES;
	return NO;
}
- (BOOL)tabView:(NSTabView *)tabView shouldAllowTabViewItem:(NSTabViewItem *)tabViewItem toLeaveTabBar:(PSMTabBarControl *)tabBarControl; {
	return NO;
}

/*
- (BOOL)outlineView:(NSOutlineView *)outlineView isGroupItem:(id)item {
	return (![[item representedObject] isLeaf]);
}
 */
#pragma mark *** Public Methods ***
#pragma mark Accessors
@synthesize projectBuildStatusTextField=_projectBuildStatusTextField,projectStatusTextField=_projectStatusTextField,outlineView=_outlineView,splitView=_splitView;

@dynamic project;
- (WCProject *)project {
	return (WCProject *)[self document];
}
#pragma mark WCTabViewContext Protocol
- (WCTextFile *)currentTextFile; {
	return [[self currentTabViewItem] identifier];
}
- (WCTextView *)currentTextView; {
	return [[[self currentTabViewItem] view] documentView];
}
- (NSTabViewItem *)currentTabViewItem; {
	return [[self tabView] selectedTabViewItem];
}
- (NSUInteger)numberOfTabViewItems; {
	return [[self tabView] numberOfTabViewItems];
}
- (NSTabView *)tabView; {
	return [_psmTabBarControl tabView];
}
- (PSMTabBarControl *)psmTabBarControl; {
	return _psmTabBarControl;
}
- (NSWindow *)contextWindow; {
	return [self window];
}
#pragma mark *** Private Methods ***
- (IBAction)_outlineViewDoubleAction:(id)sender; {
	NSTreeNode *node = [[[sender dataSource] selectedNodes] firstObject];
	
	if (![node isLeaf]) {
		if ([_outlineView isItemExpanded:node])
			[_outlineView collapseItem:node];
		else
			[_outlineView expandItem:node];
	}
	
	WCBuildMessage *bm = [node representedObject];
	
	if ([bm messageType] != WCBMTypeError && [bm messageType] != WCBMTypeWarning)
		return;
	
	WCTextFile *tf = [bm textFile];
	
	if (!tf)
		return;
	
	[[self project] addTabViewItemForTextFile:tf inTabViewContext:self];
	
	WCTextView *tv = [self currentTextView];
	
	if (!tv)
		return;
	
	NSRange range = NSMakeRange([[tv rulerView] lineStartForLineNumber:[bm lineNumber]], 0);
	
	[tv setSelectedRange:range];
	[tv scrollRangeToVisible:range];
}

- (IBAction)_textViewSymbolsPopUpButtonAction:(id)sender {
	WCSymbol *symbol = [sender representedObject];
	
	WCTextView *tv = [self currentTextView];
	NSString *string = [tv string];
	NSRange range = [string lineRangeForRange:NSMakeRange([[symbol textFile] lineStartIndexForLineNumber:[symbol lineNumber]], 0)];
	
	range = [string rangeOfString:[symbol name] options:NSLiteralSearch range:range];
	
	[tv setSelectedRange:range];
	[tv scrollRangeToVisible:[tv selectedRange]];
	[tv showFindIndicatorForRange:[tv selectedRange]];
}

- (void)_loadProjectPreferences; {
	// window frame
	NSString *string = [[[self project] projectPreferences] objectForKey:kWCProjectPrefsBuildResultsWindowFrameKey];
	if (string)
		[[self window] setFrame:NSRectFromString(string) display:NO];
	else
		[[self window] center];
	
	// split view divider position
	NSNumber *hPosition = [[[self project] projectPreferences] objectForKey:kWCProjectPrefsBuildResultsSplitViewDividerPositionKey];
	if (hPosition)
		[[self splitView] setPosition:[hPosition floatValue] ofDividerAtIndex:0];
	
	[_outlineView expandItem:[_outlineView itemAtRow:0] expandChildren:YES];
}
@end
